<template>
	<el-table :data="tableData" border stripe v-bind="$attrs">
		<!-- 左侧序号 -->
		<el-table-column v-if="indexType" :type="indexType" reserve-selection width="60" label="序号" align="center" />
		<template v-for="col in options">
			<!-- "col.sortable == undefined || col.sortable" 排序后 $index 错乱导致 编辑时数据不对 -->
			<el-table-column :label="col.label" :width="col.width" :align="col.align || 'center'" :prop="col.prop" :show-overflow-tooltip="!col.action && true" header-align="center" :sortable="col.sortable" :formatter="(col.formatter as any)">
				<template #default="scope">
					<!-- 单元格编辑, 显示编辑框 -->
					<div v-if="cellEditID === scope.$index + scope.column.id" class="editIcon">
						<slot v-if="col.useSlot" :name="col.prop" :scope="scope" :editing="true"></slot>
						<span v-else>
							<!-- 默认用 input 输入 -->
							<el-input v-model="scope.row[col.prop]" size="small" class="editIcon" />
						</span>
						<!-- 恢复显示编辑按钮 -->
						<div @click="cellEditID = ''" class="editIcon">
							<el-icon-check @click="check(scope)" style="color: green" />
							<el-icon-close @click="close(scope)" style="color: orangered" />
						</div>
					</div>
					<!--行 编辑状态-->
					<div v-else-if="rowEditIndex === scope.$index">
						<slot v-if="col.useSlot" :name="col.prop" :scope="scope" :editing="true" />
						<span v-else-if="isBoolean(scope.row[col.prop])">
							<ElCheckbox v-model="scope.row[col.prop]" :disabled="col.editable === false" />
						</span>
						<span v-else-if="isUndefined(col.editable) || col.editable === true">
							<!-- 默认用 input 输入 -->
							<el-input v-model="scope.row[col.prop]" size="small" class="editIcon" />
						</span>
						<span v-else>
							{{ scope.row[col.prop] }}
						</span>
					</div>
					<!--显示状态(不可编辑)-->
					<div v-else>
						<!-- 操作项列 -->
						<slot v-if="col.action" name="action" :scope="scope" />
						<!-- 带插槽的数据 -->
						<slot v-else-if="col.useSlot" :name="col.prop" :scope="scope" :editing="false"></slot>
						<!-- 显示数据,如果上面绑定了 prop 此行可不加,
                但是为了能定制显示内容,移除了绑定 -->
						<span v-else-if="isBoolean(scope.row[col.prop])">
							<ElCheckbox :checked="scope.row[col.prop]" :disabled="true" />
						</span>
						<!-- 客户格式化函数 -->
						<span v-else-if="col.formatter">
							{{ col.formatter(scope.row, col.prop, scope.row[col.prop], scope.$index) }}
						</span>
						<!-- 封装格式化函数 -->
						<span v-else-if="col.autoFormat">
							{{ formatter(scope.row, col.prop, scope.row[col.prop], scope.$index) }}
						</span>
						<span v-else>
							{{ scope.row[col.prop] }}
						</span>
						<!-- 编辑图标 -->
						<el-icon-edit v-if="col.editable" @click="clickEdit(scope)" />
					</div>
				</template>
			</el-table-column>
		</template>
		<!-- 行编辑功能 -->
		<el-table-column v-if="isRowEditable" label="行操作" width="136px" align="center">
			<template #default="scope">
				<div v-if="rowEditIndex === scope.$index">
					<el-button type="success" size="small" @click="confirm(scope)">确认</el-button>
					<el-button type="danger" size="small" @click="reset(scope)">重置</el-button>
				</div>
				<div v-else>
					<el-button type="success" size="small" @click="rowEdit(scope)">编辑</el-button>
					<el-button type="danger" size="small" @click="rowDel(scope)">删除</el-button>
				</div>
			</template>
		</el-table-column>
	</el-table>
	<!-- 分页显示 -->
	<el-pagination class="pagination" small v-if="pagination" @size-change="sizeChange" @current-change="currentChange" v-model:currentPage="currentPage" :page-sizes="pageSizes" :page-size="curPageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" background />
</template>

<script setup lang="ts">
import type { TableOptions } from './types'

// 格式化数字
const formatter = (row: any, col: string, cellValue: any, index: number) => {
	if (isNumber(cellValue)) {
		return Number(cellValue)
			.toFixed(2)
			.replace(/(\d)(?=(\d{3})+\.)/g, ($0, $1) => {
				return $1 + ','
			})
			.replace(/\.$/, '')
	}
	return cellValue
}

// ------------ 定义属性 ------------
const addRow = (scope: any) => {
	if (tableData.value === null) {
		// 无数据
		tableData.value = [scope]
		rowEditIndex.value = 0
	} else {
		tableData.value.push(scope)
		rowEditIndex.value = tableData.value.length - 1
	}
}

defineExpose({
	addRow,
})

let props = defineProps({
	// 表格配置
	options: {
		type: Array as PropType<TableOptions[]>,
		required: true,
	},
	// 表格数据
	dataArray: {
		type: Array as PropType<any[]>,
		required: true,
	},
	// 左边第1列的类型 "selection"|"index"|"expand"
	indexType: {
		type: String,
	},
	// 是否启用行编辑功能
	isRowEditable: {
		type: Boolean,
		default: false,
	},
	pagination: {
		type: Boolean,
		default: false,
	},
	// 分页选项
	pageSizes: {
		type: Array as PropType<number[]>,
		default: [10, 30, 50, 100],
	},
	// 每页项数
	pageSize: {
		type: Number,
		default: 10,
	},
	// 当前页
	// currentPage: {
	//   type: Number,
	//   default: 1,
	// },
	// 总页数
	total: {
		type: Number,
		default: 100,
	},
})

// ------------ 单元格内容编辑 ------------
let emits = defineEmits(['cellChanged', 'rowAdded', 'rowChanged', 'rowDeleted', 'pageSizeChanged', 'currentPageChanged', 'update:pageSize'])
// $index 行序号(0开始)  column.id 列标识
let cellEditID = ref('') // 被编辑的单元格 id
let cellEditOld = ref() // 被编辑单元格的原值
let clickEdit = (scope: any) => {
	cellEditID.value = scope.$index + scope.column.id
	cellEditOld.value = scope.row[scope.column.property]
}
// 编辑单元格的事件:由于 v-model 绑定，值已经被修改
let check = (scope: any) => {
	if (scope.row[scope.column.property] !== cellEditOld.value) {
		emits('cellChanged', scope)
	}
}
// 点击 叉叉, 恢复为原值
let close = (scope: any) => {
	scope.row[scope.column.property] = cellEditOld.value
	cellEditOld.value = ''
}

// ------------ 行编辑 ------------
// 复制数据(不能直接编辑父组件数据)
let tableData = ref<any[]>(useCloneDeep(props.dataArray))
// 数据变化
watch(
	() => props.dataArray,
	(val) => {
		tableData.value = useCloneDeep(val)
	},
	{ deep: true },
)

// 当前正在编辑行的id
let rowEditIndex = ref(-1)
// 行编辑事件
let rowEdit = (scope: any) => {
	rowEditIndex.value = scope.$index // 指定编辑行
}
// 行删除
let rowDel = (scope: any) => {
	ElMessageBox.confirm('数据行将被删除, 确认吗?', '提示', {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		type: 'warning',
	}).then(() => {
		tableData.value.splice(scope.$index, 1)
		props.dataArray.splice(scope.$index, 1)
		emits('rowDeleted', scope.row) // 通知父组件行删除了
	})
}

// 行编辑->确认
let confirm = (scope: any) => {
	rowEditIndex.value = -1 // 取消行编辑

	if (tableData.value.length > props.dataArray.length) {
		// 新加行
		emits('rowAdded', scope.row)
	} else {
		// 更新行数据:(old, new)
		emits('rowChanged', props.dataArray[scope.$index], tableData.value[scope.$index]) // 通知父组件行变化了
	}
}

// 行编辑->重置
let reset = (scope: any) => {
	if (props.dataArray === null || scope.$index == props.dataArray.length) {
		// 新加行
		tableData.value.splice(scope.$index, 1) // 删除行
	} else {
		tableData.value[scope.$index] = useCloneDeep(props.dataArray[scope.$index])
		rowEditIndex.value = -1
	}
}

// 分页功能: 每页数量变化
let curPageSize = ref(0)
// 父组件设置 pageSize 生效
onMounted(() => {
	curPageSize.value = props.pageSize
})
let sizeChange = (val: number) => {
	curPageSize.value = val
	emits('update:pageSize', val)
	emits('pageSizeChanged', val)
}
// 当前页变化
let currentPage = ref(1)
let currentChange = (val: number) => {
	currentPage.value = val
	emits('currentPageChanged', val)
}
</script>

<style scoped lang="scss">
// 单元格中的编辑按钮
svg {
	height: 1em;
	width: 1em;
	cursor: pointer;
	margin-left: 4px;
}

.editIcon {
	display: flex;

	// 编辑单元格的样式按钮中的对勾与叉叉
	svg {
		height: 1.2em;
		width: 1.2em;
		margin-top: 0.2em;
	}
}

// 分页显示
.pagination {
	display: flex;
	margin-top: 4px;
}
</style>
